﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Management;
using System.Collections;
// namespaces necesarios para conexión a bd
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing;
using System.Windows.Forms;

namespace Persistencia_y_capa_de_negocio
{
    public class CADUnidad
    {
        private static readonly CADUnidad instancia = new CADUnidad();
        public static CADUnidad Instancia
        {
            get { return instancia; }
        }

        // Cadena de conexión.
        private string cadCon;
        private SqlDataAdapter da;
        private SqlDataAdapter dae;
        private SqlConnection c;
        private DataSet vdb;

        /// <summary>
        /// Constructor.
        /// </summary>
        public CADUnidad()
        {
            try
            {
                // Establecemos la cadena de conexión desde app.config.
                cadCon = ConfigurationManager.ConnectionStrings["conexion"].ConnectionString;

                // Creamos la base de datos virtual.
                vdb = new DataSet();

                // Obtenemos una conexión.
                c = new SqlConnection(cadCon);

                // Almacenamos la base de datos en local.
                da = new SqlDataAdapter("select * from unidades", c);
                da.Fill(vdb, "Unidad");

                dae = new SqlDataAdapter("Select * from creaunidad", c);
                dae.Fill(vdb, "CreaUnidades");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

 
        }

        /// <summary>
        /// Insertamos en la base de datos una unidad
        /// </summary>
        /// <param name="ed">Variable con los datos necesarios que contiene un edificio.</param>
        public bool InsertarUnidad(ENUnidad un)
        {
            // Indica si se ha realizado la inserción.
            bool insertado = false;
            DataRow r = null;
            // Obtenemos la tabla unidad.
            DataTable t = new DataTable();
            t = vdb.Tables["Unidad"];
            
            try
            {
                // Comprobamos si ya existe una unidad con ese nombre.
                r = t.Select("nombre = \'" + un.Nombre + "\'")[0];

                // Actualizamos la información del edificio.
                r["nombre"] = un.Nombre;
                r["descripcion"] = un.Descripcion;
                r["ataque"] = un.Ataque;
                r["defensa"] = un.Defensa;
                r["vida"] = un.Vida;
                r["velocidad"] = un.Velocidad;
                r["tiempo"] = un.Tiempo;
                r["admin"] = un.Admin;
                SqlCommandBuilder command = new SqlCommandBuilder(da);

                // Actualizamos los cambios en la BD real.
                da.Update(vdb, "Unidad");
            }
            catch (Exception ex)
            {
                // Significa que el resultado ha sido null. O sea que hay que insertar, no modificar.
                r = t.NewRow();

                //MessageBox.Show(ex.Message.ToString());

                // Insertamos los valores del nuevo recurso.
                r["nombre"] = un.Nombre;
                r["defensa"] = un.Defensa;
                r["ataque"] = un.Ataque;
                r["velocidad"] = un.Velocidad;
                r["vida"] = un.Vida;
                r["tiempo"] = un.Tiempo;
                r["descripcion"] = un.Descripcion;
                r["admin"] = un.Admin;

                // Añadimos la nueva fila a la tabla virtual.
                t.Rows.Add(r);
                SqlCommandBuilder command = new SqlCommandBuilder(da);

                // Actualizamos los cambios en la BD real.
                da.Update(vdb, "Unidad");

                // Se ha realizado la inserción.
                insertado = true;
            }
            
            // Devolvemos el resultado.
            return insertado;
        }

        /// <summary>
        /// Recoje de la base de datos la tabla actividad y nos la muestra.
        /// </summary>
        /// <returns> Devuelve un ArrayList con los datos de todas las unidades.</returns>
        public ArrayList getUnidades()
        {
            // ArrayList de unidades.
            ArrayList lista = new ArrayList();

            // Obtenemos la tabla unidades.
            DataTable t = new DataTable();
            t = vdb.Tables["Unidad"];

            t.Clear();

            da = new SqlDataAdapter("select * from unidades", c);

            da.Fill(vdb, "Unidad");    // Ahora tenemos todo el contenido de edificios en local.

            t = vdb.Tables["Unidad"];

            // Extraemos los ENUnidad de cada fila de la base de datos.
            foreach (DataRow r in t.Rows)
            {
                ENUnidad un = new ENUnidad();

                // Insertamos los datos en la nueva actividad.
                un.Id = Convert.ToInt32(r["id"]);
                un.Nombre = r["nombre"].ToString().Trim();
                un.Ataque = Convert.ToInt32(r["ataque"]);
                un.Defensa = Convert.ToInt32(r["defensa"]);
                un.Velocidad = Convert.ToInt32(r["velocidad"]);
                un.Vida = Convert.ToInt32(r["vida"]);
                un.Tiempo = Convert.ToInt32(r["tiempo"]);
                un.Descripcion = r["descripcion"].ToString().Trim();
                un.Admin = r["admin"].ToString().Trim();

                //un = getUnidad(r["nombre"].ToString().Trim());

                lista.Add(un);
            }

            // Devolvemos el resultado.
            return lista;
        }

        /// <summary>
        /// Recoje de la base de las unidades que no pertenecen a la lista de excepción.
        /// </summary>
        /// <returns> Devuelve un ArrayList con los datos de las unidades no exentas.</returns>
        public ArrayList getUnidadesExcepto(ArrayList listaExcepcion)
        {
            // ArrayList de unidades.
            ArrayList lista = new ArrayList();
            
            // Obtenemos la tabla unidad.
            DataTable t = new DataTable();
            t = vdb.Tables["Unidad"];

            // Realizamos un select de aquellas que no pertenecen a la lista de excepción.
            string select = "";
            bool primero = true;
            foreach (int nombre in listaExcepcion)
            {
                if (primero == true)
                {
                    select += "id <> " + nombre + " ";
                    primero = false;
                }
                else
                {
                    select += "and id <> " + nombre + " ";
                }
            }
            try
            {
                // Extraemos los ENUnidad de cada fila de la base de datos.
                foreach (DataRow r in t.Select(select))
                {
                    ENUnidad un = new ENUnidad();

                    // Insertamos los datos en la nueva actividad.
                    un.Id = Convert.ToInt32(r["id"]);
                    un.Nombre = r["nombre"].ToString().Trim();
                    un.Ataque = Convert.ToInt32(r["ataque"]);
                    un.Defensa = Convert.ToInt32(r["defensa"]);
                    un.Velocidad = Convert.ToInt32(r["velocidad"]);
                    un.Vida = Convert.ToInt32(r["vida"]);
                    un.Tiempo = Convert.ToInt32(r["tiempo"]);
                    un.Descripcion = r["descripcion"].ToString().Trim();
                    un.Admin = r["admin"].ToString().Trim();
                    lista.Add(un);
                }
            }
            catch (Exception)
            {
                return null;
            }

            // Devolvemos el resultado.
            return lista;
        }

        /// <summary>
        /// Devuelve una unidad
        /// </summary>
        /// <param name="nombre">Nombre de la unidad que tiene que devolver</param>
        /// <returns>Devuelve un ENUnidad</returns>
        public ENUnidad getUnidad(string nombre)
        {
            // Obtenemos la tabla unidad.
            DataTable t = new DataTable();
            t = vdb.Tables["Unidad"];

            try
            {
                // Comprobamos si existe una unidad con ese nombre.
                DataRow r = t.Select("nombre = \'" + nombre + "\'")[0];

                // Creamos la unidad.
                ENUnidad un = new ENUnidad();
                un.Id = Convert.ToInt32(r["id"]);
                un.Nombre = r["nombre"].ToString().Trim();
                un.Ataque = Convert.ToInt32(r["ataque"]);
                un.Defensa = Convert.ToInt32(r["defensa"]);
                un.Velocidad = Convert.ToInt32(r["velocidad"]);
                un.Vida = Convert.ToInt32(r["vida"]);
                un.Tiempo = Convert.ToInt32(r["tiempo"]);
                un.Descripcion = r["descripcion"].ToString().Trim();

                // Devolvemos el resultado.
                return un;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString());
                return new ENUnidad();
            }
        }

        /// <summary>
        /// Devuelve el número de unidades que han sido creados por el administrador que recibe por parámetro.
        /// </summary>
        /// <param name="nombre">Nombre del administrador.</param>
        /// <returns>Devuelve un entero con la cantidad de unidades que han sido creados por el administrador.</returns>
        public int getNumUnidadesPorAdmin(string nombre)
        {
            // Obtenemos la tabla unidades.
            DataTable t = new DataTable();
            t = vdb.Tables["Unidad"];

            try
            {
                // Devolvemos la cantidad de unidades con ese creador.
                return t.Select("admin = \'" + nombre + "\'").Count();

            }
            catch (Exception)
            {
                return 0;
            }
        }

        /// <summary>
        /// Devuelve el nombre de la unidad de identificador id.
        /// </summary>
        /// <param name="id">Identificador de la unidad de la que se busca el nombre.</param>
        /// <returns>Devuelve un string con el nombre de la unidad de ese id.</returns>
        public string getNombreUnidad(int id)
        {
            // Obtenemos la tabla unidad.
            DataTable t = vdb.Tables["Unidad"];

            // Comprobamos si existe una unidad con ese id.
            DataRow r = t.Select("id = "+ id)[0];

            // Extraemos el nombre de la unidad.
            string nomb = r["nombre"].ToString();

            // Devolvemos el nombre.
            return nomb;
        }

        /// <summary>
        /// Elimina una unidad de la base de datos.
        /// </summary>
        /// <param name="nombre">nombre de la unidad que se va a eliminar.</param>
        public void EliminaUnidad(string nombre)
        {
            // Obtenemos la tabla unidad.
            DataTable t = vdb.Tables["Unidad"];

            try
            {
                // Comprobamos si existe una unidad con ese nombre.
                DataRow r = t.Select("nombre = \'" + nombre + "\'")[0];

                // La eliminamos de la base de datos.
                r.Delete();
                SqlCommandBuilder command = new SqlCommandBuilder(da);

                // Actualizamos los cambios en la BD real.
                da.Update(vdb, "Unidad");
            }
            catch(Exception ex)
            {
                // Mostrar un error.
                MessageBox.Show(ex.Message);
            }
        }

        /// <summary>
        /// Devuelve los ids de las unidades que pertenecen al edificio en cuestión
        /// </summary>
        /// <param name="edificio">Edificio del que queremos las unidades</param>
        /// <returns></returns>
        public ArrayList getUnidadesEdificio(int edificio)
        {
            // ArrayList de unidades.
            ArrayList lista = new ArrayList();

            // Obtenemos la tabla creaunidades.
            DataTable t = new DataTable();
            t = vdb.Tables["CreaUnidades"];


            foreach( DataRow r in t.Select("nomEdificio = \'" + edificio + "\'"))
            {
                int un = Convert.ToInt32(r[1]);
                lista.Add(un);
            }
            
            return lista;
        }

        /// <summary>
        /// Añade una unidad a las que puede crear el edificio.
        /// </summary>
        /// <param name="edificio">Edificio creador</param>
        /// <param name="unidad">Unidad que puede ser creada</param>
        public void AñadeUnidadEdificio(int edificio, int unidad)
        {
            DataTable t = vdb.Tables["CreaUnidades"];
            DataRow r = t.NewRow();

            r["nomedificio"] = edificio;
            r["nomunidad"] = unidad;

            //MessageBox.Show(edificio + " " + unidad);
            try
            {
                t.Rows.Add(r);

                SqlCommandBuilder command = new SqlCommandBuilder(dae);

                // Actualizamos los cambios en la BD real.
                dae.Update(vdb, "CreaUnidades");
            }
            catch
            {
                t.Rows.Remove(r);
            }

        }

        /// <summary>
        /// Insertamos en la tabla, que unidades puede crear un edificio.
        /// </summary>
        /// <param name="edificio">Edificio que creará las unidades.</param>
        /// <param name="unidades">Unidades que pueden ser creadas.</param>
        public void AnadeUnidadesEdificio(int edificio, ArrayList unidades)
        {
            DataTable t = vdb.Tables["CreaUnidades"];   // Tabla antes de insertar lo nuevo.

            DataRow[] filas = t.Select("nomedificio = \'" + edificio + "\'");

            // Eliminamos las que ya no estén
            foreach (DataRow r in filas)
            {
                if (!unidades.Contains(r["nomunidad"]))
                {
                    // Si no lo contiene habrá que eliminar en la tabla.
                   r.Delete();
                }
            }

            SqlCommandBuilder command = new SqlCommandBuilder(dae);

            // Actualizamos los cambios en la BD real.
            dae.Update(vdb, "CreaUnidades");

            // Ahora insertamos las nuevas.
            foreach (int s in unidades)
            {
                AñadeUnidadEdificio(edificio, s);
            }
        }
        
        /// <summary>
        /// Elimina una unidad de las que puede crear el edificio.
        /// </summary>
        /// <param name="edificio">Edificio creador</param>
        /// <param name="unidad">Unidad que ya no puede ser creada</param>
        public void EliminaUnidadEdificio(string edificio, string unidad)
        {
            DataTable t = vdb.Tables["CreaUnidades"];
            string select = "nomedificio = \'" + edificio + "\' and nomunidad = \'" + unidad + "\'";

            try
            {
                DataRow r = t.Select(select)[0];
                r.Delete();

                SqlCommandBuilder command = new SqlCommandBuilder(dae);

                // Actualizamos los cambios en la BD real.
                dae.Update(vdb, "CreaUnidades");
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        public int getNumUnidades()
        {
            DataTable t = new DataTable();
            t = vdb.Tables["Unidad"];
            return t.Rows.Count;
        }

        /// <summary>
        /// Función que devuelve un arrayList de unidades mediante criterios de búsqueda
        /// </summary>
        /// <param name="nombre">nombre de la unidad</param>
        /// <param name="vida">vida de la unidad</param>
        /// <param name="defensa">defensa de la unidad</param>
        /// <param name="ataque">ataque de la unidad</param>
        /// <param name="velocidad">velocidad de la unidad</param>
        /// <param name="tiempo">tiempo de generación de la unidad</param>
        /// <returns></returns>
        public ArrayList getUnidadesBuscar(string nombre, string vida, string defensa, string ataque, string velocidad, string tiempo)
        {
            DataTable t = vdb.Tables["Unidad"];
            string select = "";
            ArrayList lista = new ArrayList();

            if (nombre != "")
            {
                select += "nombre like \'%" + nombre + "%\' ";
            }
            if (vida != "")
            {
                if (nombre != "")
                {
                    select += " and ";
                }
                select += "vida = " + vida + " ";
            }
            if (defensa != "")
            {
                if (nombre != "" || vida != "")
                {
                    select += " and ";
                }
                select += "defensa = " + defensa + " ";
            }
            if (ataque != "")
            {
                if (nombre != "" || vida != "" || defensa != "")
                {
                    select += " and ";
                }
                select += "ataque = " + ataque + " ";
            }
            if (velocidad != "")
            {
                if (nombre != "" || vida != "" || defensa != "" || ataque != "")
                {
                    select += " and ";
                }
                select += "velocidad = " + velocidad + " ";
            }
            if (tiempo != "")
            {
                if (nombre != "" || vida != "" || defensa != "" || ataque != "" || velocidad != "")
                {
                    select += " and ";
                }
                select += "tiempo = " + tiempo + " ";
            }

            

            foreach (DataRow r in t.Select(select))
            {
                ENUnidad un = CADUnidad.Instancia.getUnidad(r["nombre"].ToString());
                lista.Add(un);
            }

            return lista;
        }
    }
}
